/*
 * Esb
 */
package ocp.bundles.esb.impl;

import java.util.Hashtable;
import java.util.Random;
import java.util.Vector;
import ocp.service.ContextConsumer;
import ocp.service.ContextService;
import ocp.context.Context;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

/**
 * Clase que representa un consumidor de contextos de tipo Medicamento
 * @author Paco Lopez Marmol
 */
public class Esb implements ContextConsumer,Runnable {

    private static final Object SCREEN_MUTEX = new Object();
    
    private String name;
    private ContextService cs;
    private ServiceRegistration sr;
    private Thread thread;
    private boolean running = false;
    
    String medicamentoContextId = null;
    
    /**
     * Constructor 
     * @param name nombre del modulo
     * @param bc BundleContex 
     */
    public Esb( String name , BundleContext bc ) {
        this.name = name;
        this.thread = new Thread(this);
        
        // Registra el servicio ContextConsumer
        Hashtable props = new Hashtable();
        props.put("id",  name ); 
        sr = bc.registerService( ContextConsumer.class.getName(), this , props );
    }
    
    /**
     * Activa el thread
     */
    public void start() {
       running = true; 
       this.thread.start();   
    }
    
    /**
     * Para el thread y quita el registro del servicio 
     */
    public void stop()  {
        
        running = false;
        try {
            thread.join();
        } catch (InterruptedException e) {
        }
        name = null;
        thread = null;
        sr.unregister();  // opcional
    }
    
    /**
     * Hilo del thread
     */
    public void run() {

        Random r = new Random();

        while (running) {
            
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ex) {  }
        
            if( r.nextFloat() < 0.25  )  {  // con probabilidad del 25%
                
                // Si tenemos el interfaz de servicio y un id de contexto
                if( cs != null && medicamentoContextId!=null )  {
                    // leemos el contexto de OCP
                    Context context = cs.read( medicamentoContextId );
                    // lo mostramos por pantalla
                    printContext(context,"(read)");
                }
            }
            
        }
        
    }
    

    /**
     * Muestra los datos de un contexto por la consola
     * @param context Contexto para mostrar
     * @param title Titulo para mostrar al principio
     */
    private void printContext(Context context, String title){ 
        
        // Encapsulamos el contexto
        ContextoMedicamento contexto = new ContextoMedicamento( context );
        
        synchronized (SCREEN_MUTEX) {
            // mostramos el contexto con sus atributos por consola
            contexto.printContext( "ESB: ", "Contexto " + title );
            
            // mostramos el número de contextos almacenados en el historico
            int nHistorico = cs.getHistoricalContextLenght(context.getId());
            System.out.println( " Elementos en el historico: " + nHistorico );
            
            // Si tenemos al menos 2 elementos los mostramos
            if( nHistorico >=2 )  {
            
                // Obtenemos los últimos 2 contextos introducidos con el id de 'context'
                Vector<Context> hContextos = cs.readHistoricalContextLast(context.getId(),2);
                /*
                    hContextos[0] es el contexto anterior
                    hContextos[1] es el contexto actual
                */ 
                
                /*
                ContextoMedicamento cAnterior = new ContextoMedicamento( hContextos.elementAt(0) );
                ContextoMedicamento cActual = new ContextoMedicamento( hContextos.elementAt(1) );
                if(  !cAnterior.getLocalizacion().equals( cActual.getLocalizacion() )  )  {
                    // la localización cambió
                               System.out.println( "La Localizacion cambio " );
                }
                */
                

                // Mostramos los dos contextos
                for( int i=0; i<2;i++)  {
                    Context c = hContextos.elementAt(i);
                    // encapsulamos el contexto c para que obtenga los attributos
                    ContextoMedicamento m = new ContextoMedicamento( c );
                    // mostramos por pantalla algunos datos
                    System.out.println( "Contexto Historico: " + m.getContextId() 
                                        + " localizacion: " + m.getLocalizacion() 
                                        
                                        );
                    
                }
            }
            System.out.println( " " );
        }
    }

    /**
     * Activa el ContextConsumer. Mensaje desde ocp para indicarnos que ya
     * podemos hacer uso del servicio ContextService.
     * @param cs Interfaz del servicio ContextService
     * @see ContextService
     */ 
    public void activate(ContextService cs) {
        this.cs = cs;
        
        // Nos registramos a los contextos de tipo Medicamento
        cs.registerToContextType( "Medicamento", this );
    }

    /**
     * Desactiva el ContextConsumer. Mensaje desde ocp para indicarnos que el
     * servicio ocp no esta disponible.
     */
    public void deactivate() {
        cs = null;
    }

    /**
     * En caso de que el ContextConsumer se haya subscrito a los cambios de un 
     * contexto, o un grupo de contextos, ocp nos notificará enviandonos el 
     * contexto actualizado.
     * @param context Contexto que cambia
     */
    public void notifyContextChange(Context context) {
        printContext(context,"(notifyContextChange)");
    }

    /**
     * ocp nos notifica de los contextos nuevos creados en el sistema
     * @param context Contexto nuevo introducido en ocp
     */
    public void notifyNewContext(Context context) {
        
        // si no es de tipo Medicamento ignoralo
        if( !context.getType().equals("Medicamento") ) return;
        
        printContext(context,"(notifyNewContext)");
            
        if( medicamentoContextId == null )  {  // si no tenemos un id 
            // Guardamos el id del contexto para leerlo más tarde
            medicamentoContextId = new String( context.getId() );
        }
    }

    /**
     * Obtiene el identificador del ContextConsumer. 
     * @return el identificador
     */
    public String getId() {
        return name;
    }
}
